/*
 * LTE Game Engine
 * Copyright (C) 2006-2008 SiberianSTAR <haxormail@gmail.com>
 * http://www.ltestudios.com
 *  
 * The LTE Game Engine is based on Irrlicht 1.0
 * Irrlicht Engine is Copyright (C) 2002-2006 Nikolaus Gebhardt
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
 
// This file was written by Jonas Petersen and modified by Nikolaus Gebhardt.
// See CLMTSMeshFileLoder.h for details.
/*

   CLMTSMeshFileLoader.cpp

   LMTSMeshFileLoader
   Written by Jonas Petersen (a.k.a. jox)

   Version 1.5 - 15 March 2005

   Get the latest version here: http://development.mindfloaters.de/

   This is an addon class for the engine engine by Nikolaus Gebhardt (http://engine.sourceforge.net).
   With this release the engine engine is at version 0.6

   This class allows loading meshes with lightmaps (*.lmts + *.tga files) that were created
   using Pulsar LMTools by Lord Trancos (http://www.geocities.com/dxlab/index_en.html)

   Notes:
   - This version does not recognice/support user data in the *.lmts files.
   - The lightmap TGA's generated by LMTools doesn't work in engine for some reason (the
   lightmaps look messed up). Opening and resaving them in a graphics app will solve
   the problem (tested only with Photoshop).


   License:
   --------

   It's free. You are encouraged to give me credit if you use it in your software.

   Version History:
   ----------------

   Version 1.5 - 15 March 2005
   - Added the switch LMTS_INTEGRATED_IN_engine. This was needed because
   of access problems to the engine Logger.
   - Did a better cleanup. No memory leaks in case of an loading error.
   - Added "#include <stdio.h>" for sprintf.

   Version 1.4 - 12 March 2005
   - Fixed bug in texture and subset loading code that would possibly cause crash.
   - Fixed memory cleanup to avoid leak when loading more then one mesh
   - Used the engine Logger instead of cerr to output warnings and errors.
   For this I had to change the constructor
   from:
   	CLMTSMeshFileLoader(io::IFileSystem* fs, video::IVideoDriver* driver)
   to:
   	CLMTSMeshFileLoader(engineDevice* device)

   Version 1.3 - 15 February 2005
   - Fixed bug that prevented loading more than one different lmts files.
   - Removed unnecessary "#include <os.h>".
   - Added "std::" in front of "cerr". This was necessary for Visual Studio .NET,
   I hope it's not disturbing other compilers.
   - Added warning message when a texture can not be loaded.
   - Changed the documentation a bit (minor).

   Version 1.2
   - To avoid confusion I skipped version 1.2 because the website was offering
   version 1.2 even though it was only version 1.1. Sorry about that.

   Version 1.1 - 29 July 2004
   - Added setTexturePath() function
   - Minor improvements

   Version 1.0 - 29 July 2004
   - Initial release


 */
//////////////////////////////////////////////////////////////////////

#include <string.h>
#include <SMeshBufferLightMap.h>
#include <SAnimatedMesh.h>
#include <SMeshBuffer.h>
#include <engineString.h>
#include <IStringParameters.h>
#include <engineDevice.h>
#include <stdio.h>
#include "CLMTSMeshFileLoader.h"
#if LMTS_INTEGRATED_IN_engine
#include "os.h"
#endif

namespace engine
{
namespace scene
{

#if LMTS_INTEGRATED_IN_engine

CLMTSMeshFileLoader::CLMTSMeshFileLoader(io::IFileSystem* fs, video::IVideoDriver* driver,
                                         IStringParameters* parameters)
	: Textures(NULL), Subsets(NULL), Triangles(NULL), NumTextures(0), NumLightMaps(0),
	TextureIDs(NULL), Mesh(0), Driver(driver), FileSystem(fs), Parameters(parameters)
{
	if (Driver)
		Driver->grab();

	if (FileSystem)
		FileSystem->grab();
}

#else

CLMTSMeshFileLoader::CLMTSMeshFileLoader(engineDevice* device)
	: Textures(0), Subsets(0), Triangles(0), NumTextures(0), NumLightMaps(0),
	TextureIDs(0), Mesh(NULL), Logger(NULL), Parameters(0)
{

	FileSystem = device->getFileSystem();
	FileSystem->grab();

	Driver = device->getVideoDriver();
	Driver->grab();

	Logger = device->getLogger();
	Parameters = device->getSceneManager()->getParameters();
}

#endif

CLMTSMeshFileLoader::~CLMTSMeshFileLoader() {
	if (Mesh)
		Mesh->drop();

	if (Driver)
		Driver->drop();

	if (FileSystem)
		FileSystem->drop();
}

void CLMTSMeshFileLoader::cleanup() {
	delete [] Textures;
	delete [] TextureIDs;
	delete [] Subsets;
	delete [] Triangles;
}

bool CLMTSMeshFileLoader::isALoadableFileExtension(const c8* filename) {
	return strstr(filename, ".lmts") != 0;
}

#include <pspdebug.h>
#define printf pspDebugScreenPrintf

IAnimatedMesh* CLMTSMeshFileLoader::createMesh(engine::io::IReadFile* file) {
//	printf("""Funzione chiamata 2\n");
	u32 i;
	u32 id;

	file->seek(0);

	// HEADER

	file->read(&Header, sizeof(SLMTSHeader));
	if (Header.MagicID != 0x53544D4C) { // "LMTS"
		LMTS_LOG("LMTS ERROR: wrong header magic id!", ELL_ERROR);
		return 0;
	}

	// TEXTURES

	file->read(&id, sizeof(u32));
	if (id != 0x54584554) { // "TEXT"
		LMTS_LOG("LMTS ERROR: wrong texture magic id!", ELL_ERROR);
		return 0;
	}

	Textures = new SLMTSTextureInfoEntry[Header.TextureCount];
	TextureIDs = new u16[Header.TextureCount];

	NumLightMaps = NumTextures = 0;

	for (i=0; i<Header.TextureCount; i++) {
		file->read(&Textures[i], sizeof(SLMTSTextureInfoEntry));
		if (Textures[i].Flags & 1) {
			TextureIDs[i] = NumLightMaps;
			NumLightMaps++;
		} else {
			TextureIDs[i] = NumTextures;
			NumTextures++;
		}

	}

	// SUBSETS

	file->read(&id, sizeof(u32));
	if (id != 0x53425553) { // "SUBS"
		LMTS_LOG("LMTS ERROR: wrong subset magic id!", ELL_ERROR);
		cleanup();
		return 0;
	}

	Subsets = new SLMTSSubsetInfoEntry[Header.SubsetCount];

	for (i=0; i<Header.SubsetCount; i++) {
		file->read(&Subsets[i], sizeof(SLMTSSubsetInfoEntry));
	}

	// TRIANGLES

	file->read(&id, sizeof(u32));
	if (id != 0x53495254) { // "TRIS"
		LMTS_LOG("LMTS ERROR: wrong triangle magic id!", ELL_ERROR);
		cleanup();
		return 0;
	}

	Triangles = new SLMTSTriangleDataEntry[(Header.TriangleCount*3)];

	for (i=0; i<(Header.TriangleCount*3); i++) {
		file->read(&Triangles[i], sizeof(SLMTSTriangleDataEntry));
	}

	/////////////////////////////////////////////////////////////////

	constructMesh();

	loadTextures();

	cleanup();

	SAnimatedMesh* am = new SAnimatedMesh();
	am->Type = EAMT_LMTS; // not unknown to engine anymore

	am->addMesh(Mesh);
	am->recalculateBoundingBox();
	Mesh->drop();
	Mesh = 0;
	return am;

}

void CLMTSMeshFileLoader::constructMesh()
{
	s32 i;

	if (Mesh)
		Mesh->drop();

	Mesh = new SMesh();

	for (i=0; i<Header.SubsetCount; i++) {

		scene::SMeshBufferLightMap* meshBuffer = new scene::SMeshBufferLightMap();

		meshBuffer->Material.MaterialType = video::EMT_LIGHTMAP; // EMT_LIGHTMAP_M2/EMT_LIGHTMAP_M4 also possible
		meshBuffer->Material.Wireframe = false;
		meshBuffer->Material.Lighting = false;
		meshBuffer->Material.BilinearFilter = true;

		Mesh->addMeshBuffer(meshBuffer);

		meshBuffer->drop();

		u32 offs = Subsets[i].Offset * 3;

		for (u32 sc=0; sc<Subsets[i].Count; sc++) {

			s32 idx = meshBuffer->getVertexCount();

			for (s32 vu=0; vu<3; ++vu)
			{
				video::S3DVertex2TCoords currentVertex;
				SLMTSTriangleDataEntry *v = &Triangles[offs+(3*sc)+vu];

				currentVertex.Color.set(255,255,255,255);

				currentVertex.Pos.X = v->X;
				currentVertex.Pos.Y = v->Y;
				currentVertex.Pos.Z =  v->Z;
				currentVertex.TCoords.X = v->U1;
				currentVertex.TCoords.Y = v->V1;
				//		 currentVertex.TCoords2.X = v->U2;
//				currentVertex.TCoords2.Y = v->V2;

				meshBuffer->Vertices.push_back(currentVertex);
			}

			meshBuffer->Indices.push_back(idx);
			meshBuffer->Indices.push_back(idx+1);
			meshBuffer->Indices.push_back(idx+2);
		}
	}

	for (u32 j=0; j<Mesh->MeshBuffers.size(); ++j)
		((SMeshBufferLightMap*)Mesh->MeshBuffers[j])->recalculateBoundingBox();

	Mesh->recalculateBoundingBox();
}

void CLMTSMeshFileLoader::loadTextures()
{
	if (!Driver || !FileSystem)
		return;

	core::stringc s;

	// load textures

	core::array<video::ITexture*> tex;
	tex.set_used(NumTextures);

	core::array<video::ITexture*> lig;
	lig.set_used(NumLightMaps);

	s32 t;
	s32 tx_count = 0;
	s32 lm_count = 0;
	core::stringc Path = Parameters->getParameter(LMTS_TEXTURE_PATH);

	for (t=0; t<Header.TextureCount; t++)
	{
		video::ITexture* tmptex = 0;
		s = Path;
		s.append(Textures[t].Filename);

		if (FileSystem->existFile(s.c_str()))
			tmptex = Driver->getTexture(s.c_str());
		else
		{
			char buf[300]; // filenames my be 256 bytes long
			sprintf(buf, "LMTS WARNING: Texture does not exist: %s", s.c_str());
			LMTS_LOG(buf, ELL_WARNING);
		}


		if (Textures[t].Flags & 1) {
			lig[lm_count++] = tmptex;
		} else {
			tex[tx_count++] = tmptex;
		}

	}

	// attach textures to materials.

	s32 i;
	for (i=0; i<Header.SubsetCount; i++)
	{
		SMeshBufferLightMap* b = (SMeshBufferLightMap*)Mesh->getMeshBuffer(i);

		if (Subsets[i].TextID1 < Header.TextureCount)
			b->Material.Texture1 = tex[TextureIDs[Subsets[i].TextID1]];
		if (Subsets[i].TextID2 < Header.TextureCount)
			b->Material.Texture2 = lig[TextureIDs[Subsets[i].TextID2]];

		if (!b->Material.Texture2)
			b->Material.MaterialType = video::EMT_SOLID;
	}

}


} // end namespace scene
} // end namespace engine
